package dao

import (
	"errors"
	"order_srv/basic/config"
	__ "order_srv/basic/orderproto"
	"order_srv/handler/dispatch"
	"order_srv/handler/models"
	"strconv"
	"time"
)

// DispatchConfigCreateOrUpdate 创建或更新派单配置
func DispatchConfigCreateOrUpdate(in *__.DispatchConfigCreateOrUpdateReq) (models.DispatchConfig, error) {
	var err error
	var dispatchOrder models.DispatchConfig
	var user models.User
	user.Id = uint64(in.UserId)
	if err = user.GetUserId(); err != nil {
		return dispatchOrder, errors.New("用户Id不存在")
	}
	if user.CType != 1 {
		return dispatchOrder, errors.New("当前管理员没有实名")
	}
	if user.UserRole != 3 {
		return dispatchOrder, errors.New("当前不是管理员")
	}
	dispatchOrder.UserId = uint32(user.Id)
	dispatchOrder.CityId = in.CityId
	dispatchOrder.Strategy = in.Strategy
	dispatchOrder.MaxDistanceKm = float64(in.MaxDistanceKM)
	dispatchOrder.ScoreWeightDistance = float64(in.ScoreWeightDistance)
	dispatchOrder.ScoreWeightRating = float64(in.ScoreWeightRating)
	dispatchOrder.ScoreWeightAccept = float64(in.ScoreWeightAccept)
	dispatchOrder.DayStartHour = int64(int(in.DayStartHour))
	dispatchOrder.NightStartHour = int64(int(in.NightStartHour))
	dispatchOrder.TimeWindowMinutes = int64(int(in.TimeWindowMinutes))
	dispatchOrder.GrayGroups = in.GrayGroups
	dispatchOrder.Version = in.Version
	dispatchOrder.UpdatedAt = time.Now()
	if err := dispatchOrder.Create(nil); err != nil {
		return dispatchOrder, errors.New("save dispatch config failed")
	}
	// 刷新缓存
	_ = config.Rdb.Del(config.Ctx, "dispatch_cfg:"+itoa(in.CityId)).Err()
	// 审计
	_ = (&models.DispatchAudit{CityId: in.CityId, TargetType: "config", TargetKey: in.Version, Operator: "admin", ChangeLog: "upsert"}).Create(nil)
	return dispatchOrder, err
}

// DispatchConfigGet 获取派单配置

func DispatchConfigGet(in *__.DispatchConfigGetReq) dispatch.Params {
	cityId := parseUint32(strconv.Itoa(int(in.CityId)))
	p, _ := dispatch.GetParamsForCity(in, config.Ctx, cityId)
	return p
}

// DispatchConfigDelete 删除派单配置
func DispatchConfigDelete(in *__.DispatchConfigDeleteReq) (models.DispatchConfig, error) {
	var err error
	var dispatchOrder models.DispatchConfig
	var user models.User
	user.Id = uint64(in.UserId)
	if err = user.GetUserId(); err != nil {
		return dispatchOrder, errors.New("用户Id不存在")
	}
	if user.CType != 1 {
		return dispatchOrder, errors.New("当前管理员没有实名")
	}
	if user.UserRole != 3 {
		return dispatchOrder, errors.New("当前不是管理员")
	}
	cityId := parseUint32(strconv.Itoa(int(in.CityId)))
	if err := config.DB.Where("city_id = ?", cityId).Delete(&models.DispatchConfig{}).Error; err != nil {
		return dispatchOrder, errors.New("删除失败")
	}
	// 刷新缓存
	_ = config.Rdb.Del(config.Ctx, "dispatch_cfg:"+itoa(cityId)).Err()
	// 审计
	_ = (&models.DispatchAudit{CityId: cityId, TargetType: "config", TargetKey: "", Operator: "admin", ChangeLog: "delete"}).Create(nil)
	return dispatchOrder, nil
}

// DispatchGrayPublish 发布灰度配置
func DispatchGrayPublish(in *__.DispatchGrayPublishReq) (models.DispatchConfig, error) {
	var dispatchPublish models.DispatchConfig
	var user models.User
	user.Id = uint64(in.UserId)
	if err := user.GetUserId(); err != nil {
		return dispatchPublish, errors.New("用户Id不存在")
	}
	if user.CType != 1 {
		return dispatchPublish, errors.New("当前管理员没有实名")
	}
	if user.UserRole != 3 {
		return dispatchPublish, errors.New("当前不是管理员")
	}
	dispatchPublish.CityId = in.CityId
	if err := config.DB.Model(&dispatchPublish).Where("city_id = ?", in.CityId).Updates(map[string]interface{}{"version": in.Version, "gray_groups": in.GrayGroups}).Error; err != nil {
		return dispatchPublish, errors.New("publish dispatch config failed: " + err.Error())
	}
	// 刷新缓存
	_ = config.Rdb.Del(config.Ctx, "dispatch_cfg:"+itoa(in.CityId)).Err()
	// 审计
	_ = (&models.DispatchAudit{CityId: in.CityId, TargetType: "gray", TargetKey: in.Version, Operator: "admin", ChangeLog: "publish:" + in.GrayGroups}).Create(nil)
	return dispatchPublish, nil
}

// DispatchGrayRollback 灰度回滚
func DispatchGrayRollback(in *__.DispatchGrayRollbackReq) (uint32, error) {
	var dispatchRollback models.DispatchConfig
	var user models.User
	user.Id = uint64(in.UserId)
	if err := user.GetUserId(); err != nil {
		return 0, errors.New("用户Id不存在")
	}
	if user.CType != 1 {
		return 0, errors.New("当前管理员没有实名")
	}
	if user.UserRole != 3 {
		return 0, errors.New("当前不是管理员")
	}
	dispatchRollback.CityId = in.CityId
	if err := config.DB.Model(&dispatchRollback).Where("city_id = ?", in.CityId).Updates(map[string]interface{}{"version": in.Version}).Error; err != nil {
		return dispatchRollback.CityId, errors.New("rollback dispatch config failed: " + err.Error())
	}
	// 刷新缓存
	_ = config.Rdb.Del(config.Ctx, "dispatch_cfg:"+itoa(in.CityId)).Err()
	// 审计
	_ = (&models.DispatchAudit{CityId: in.CityId, TargetType: "gray", TargetKey: in.Version, Operator: "admin", ChangeLog: "rollback"}).Create(nil)
	return dispatchRollback.CityId, nil
}

// DispatchAuditQuery 查询派单配置审计
func DispatchAuditQuery(in *__.DispatchAuditQueryReq) ([]*__.DispatchAudit, error) {
	cityId := parseUint32(strconv.Itoa(int(in.CityId)))
	version := in.Version
	q := config.DB.Model(&models.DispatchAudit{})
	if cityId != 0 {
		q = q.Where("city_id = ?", cityId)
	}
	if version != "" {
		q = q.Where("target_key = ?", version)
	}
	var list []models.DispatchAudit
	var List []*__.DispatchAudit
	if err := q.Order("id desc").Limit(200).Find(&list).Error; err != nil {
		return nil, err
	}
	for _, v := range list {
		List = append(List, &__.DispatchAudit{
			Id:         int64(v.Id),
			CityId:     v.CityId,
			TargetType: v.TargetType,
			TargetKey:  v.TargetKey,
			Operator:   v.Operator,
			ChangeLog:  v.ChangeLog,
		})
	}
	return List, nil
}

// itoa 将 uint32 转换为字符串
func itoa(u uint32) string {
	if u == 0 {
		return "0"
	}
	b := make([]byte, 0, 10)
	for u > 0 {
		b = append(b, byte('0'+u%10))
		u /= 10
	}
	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
		b[i], b[j] = b[j], b[i]
	}
	return string(b)
}

// parseUint32 将字符串转换为 uint32
func parseUint32(s string) uint32 {
	var n uint64
	for i := 0; i < len(s); i++ {
		c := s[i]
		if c < '0' || c > '9' {
			return 0
		}
		n = n*10 + uint64(c-'0')
	}
	if n > 4294967295 {
		return 0
	}
	return uint32(n)
}
